General description
This package allows an easy implementation of a client/server application using TCP/IP connections over a network. It has been successfully tested on the following systems :
This package has been developped using a C++ compiler ; gcc on Unix systems and Microsoft Visual C++ 5.0 for NT.
Registration
This package is shareware, not freeware. If you do not register your version of these libraries :
Number of licences : unlimited.
Upgrades : free
Assistance : an assistance can be provided.
You can contact me for any additionnal information about registration : Didier.Cassereau@espci.fr
Known problems
Some knows problems may require some specific configurations :
The XDR mechanism
The XDR mechanism allows to insure that the binary representation of
data can be understood by the different clients and servers connected to
the network, independantly of their own operating systems.
Each system implements some encoding and decoding functions that must
be used before transmission (encoding) and after reception (decoding).
From these basic XDR functions, you can develop your own XDR routines
for your own objects.
Compiling an application using this package
To use this package, you must have :
Linux system : the server must be linked with the pthread library
server.o : server.cpp
g++ -c server.cpp
client : client.o
g++ -o client client.o
-lrpcdc
client.o : client.cpp
c++ -c client.cpp
server.o : server.cpp
g++ -c server.cpp
client : client.o
g++ -o client client.o
-lrpcdc
client.o : client.cpp
c++ -c client.cpp
server.o : server.cpp
g++ -c server.cpp
client : client.o
g++ -o client client.o
-lrpcdc
client.o : client.cpp
c++ -c client.cpp
This package has been tested with Microsoft Visual C++ 5.0 only.
Just create a project including your source files, and link your program
with rpcdc.lib. Depending on your source code, you can have to
specify an additional library wsock32.lib.
When running your application, be sure that your program can find rpcdc.dll
!
Server example
Here is a listing of a simple server that is able to manage tcp
and udp requests.
//-----------------------------------------------------------------------------
// This program illustrates a simple server implementation
// The server is listening on the tcp and udp ports
//-----------------------------------------------------------------------------
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <math.h>
#include <rpcdc.h>
//-----------------------------------------------------------------------------
// Here is a definition of a structure that must be transmitted
to the server
// One possibility is to develop a specific XDR function, used
with transmit/
// receive functions
//-----------------------------------------------------------------------------
typedef struct _TEST {
int i1;
int i2;
int i3;
float f;
double d;
} TEST;
//-----------------------------------------------------------------------------
// First write the XDR function - standard structure
// The parameters are as follows :
// h : (void *) points to the host
binary representation of the data
// n : (void *) points to the network
binary representation of the data
// code : indicates the operation
to perform (3 possibilities)
//
--> XDR_ENCODE : conversion h -> n
//
--> XDR_DECODE : conversion n -> h
//
--> XDR_MEMORY : just returns the size of the object
//-----------------------------------------------------------------------------
size_t _xdr_TEST (void *h, void *n, int code)
{
TEST *hi=(TEST *)h;
// first convert pointers
char *ni=(char *)n;
size_t size;
switch (code) {
case XDR_ENCODE:
case XDR_DECODE:
size=_xdr_int(NULL,NULL,XDR_MEMORY);
_xdr_int((void *)&hi->i1,(void
*)ni,code); ni+=size;
_xdr_int((void *)&hi->i2,(void
*)ni,code); ni+=size;
_xdr_int((void *)&hi->i3,(void
*)ni,code); ni+=size;
size=_xdr_float(NULL,NULL,XDR_MEMORY);
_xdr_float((void *)&hi->f,(void
*)ni,code); ni+=size;
size=_xdr_double(NULL,NULL,XDR_MEMORY);
_xdr_double((void *)&hi->d,(void
*)ni,code); ni+=size;
return 0;
case XDR_MEMORY:
default:
return 3*_xdr_int(NULL,NULL,XDR_MEMORY)+
_xdr_float(NULL,NULL,XDR_MEMORY)+
_xdr_double(NULL,NULL,XDR_MEMORY);
}
}
//-----------------------------------------------------------------------------
// Now the function to send a TEST structure becomes very simple
!
// The following example returns 1 if success, 0 if a problem occurs.
// Binary conversion is automatically performed through the XDR
routine
// written above.
// Warning : remember to call _rpc_flush() !
//-----------------------------------------------------------------------------
int _rpcsend_TEST (SOCKET Socket,
RPC_MSG *rpc_msg, XDR_BUFFER *xdr_buffer,
TEST *TestParameter)
{
return _rpcsend_buffer(Socket,rpc_msg,xdr_buffer,TestParameter,_xdr_TEST)==
_xdr_TEST(NULL,NULL,XDR_MEMORY);
}
//-----------------------------------------------------------------------------
// Similarly, the function to receive a TEST structure is also
simple.
// Binary conversion is automatically performed through the XDR
routine
// written above.
//-----------------------------------------------------------------------------
int _rpcrecv_TEST (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
TEST *TestParameter)
{
return _rpcrecv_buffer(Socket,xdr_buffer,TestParameter,_xdr_TEST)==
_xdr_TEST(NULL,NULL,XDR_MEMORY);
}
//-----------------------------------------------------------------------------
// This is one of the most important functions : each time a message
is
// received by the server, this function is called
// The first parameter rpc_func identifies the message
// The second parameter idClient identifies the client (the server
can accept
// connections with multiple clients at the same time)
//-----------------------------------------------------------------------------
static void Dispatch (int rpc_func, int idClient)
{
SOCKET socket;
RPC_MSG *rpc_msg;
XDR_BUFFER *xdr_buffer;
char *client_buffer;
int I;
TEST Test;
// The first thing to do is to retrieve the parameters of the client
_GetClientInfo(idClient,
&socket,
&rpc_msg,
&xdr_buffer,
&client_buffer);
// Now, the function reduces to a big switch depending of the value
of rpc_func
switch (rpc_func) {
// First kind of message (prefer constants defined by #define instead
of numerical constants)
// This message requires to read additionnal parameters (int +
TEST strcuture) from the socket
// The response of the server to the client : just add 1 to the
int sent by the client, and then return it
// Similar changes to the TEST structure
// Note the call to _rpc_flush() !
case 1:
_rpcrecv_int(socket,xdr_buffer,&I);
_rpcrecv_TEST(socket,xdr_buffer,&Test);
printf("Data received
from client : %d\n",I);
printf("TEST structure
: %d %d %d %g %lg\n",Test.i1,Test.i2,Test.i3,Test.f,Test.d);
// Now change the values
I++;
Test.i1*=2;
Test.i2*=3;
Test.i3*=4;
Test.f=1.0f/Test.f;
Test.d=sqrt(Test.d);
// Now returns to changes parameters to client
_rpcsend_int(socket,rpc_msg,xdr_buffer,I);
_rpcsend_TEST(socket,rpc_msg,xdr_buffer,&Test);
_rpc_flush(socket,rpc_msg);
break;
// Other messages and associated code ...
default:
return;
}
}
//-----------------------------------------------------------------------------
// This accepts or not a connection from one client on the network,
whose ip
// address is transmitted as a character string parameter. The
return value is
// 0 (connection refused) or 1 (connection accepted)
//-----------------------------------------------------------------------------
static int AcceptConnection (char *ip)
{
return 1;
}
//-----------------------------------------------------------------------------
// This function is called each time a message is received on the
udp socket
// of the server (if it exists).
// In this example, the server sends an answer made of one long
int, followed
// by a 128 characters string.
//-----------------------------------------------------------------------------
void udpManager (SOCKET udpSocket)
{
sockaddr_in src_addr;
long int udpQuery;
int stat,len;
struct {
long int udpResponse;
char szb[128];
} udp;
// First I read the data from the udp socket. In this example, the
client is assumed to send
// only a 32 bits message
len=sizeof(src_addr);
stat=recvfrom(udpSocket,(char *)&udpQuery,sizeof(long
int),0,(struct sockaddr *)&src_addr,&len);
if (stat!=sizeof(long int)) return;
// Note the use of ntohl(), required by the XDR mechanism
udpQuery=ntohl(udpQuery);
// Depending on the received message, I generate the answer, replying
(udpQuery+1)
switch (udpQuery) {
case 1:
udp.udpResponse=htonl(1+udpQuery);
// response=query+1
strcpy(udp.szb,"udp
query #1"); // text of the response
break;
default:
udp.udpResponse=htonl(0);
// response=0
strcpy(udp.szb,"");
// empty text
}
// Now send the response to the client who sent the udp request
sendto(udpSocket,(char *)&udp,sizeof(udp),MSG_DONTROUTE,(struct
sockaddr *)&src_addr,sizeof(sockaddr_in));
}
//-----------------------------------------------------------------------------
// This function starts the server with a specific service
//-----------------------------------------------------------------------------
static void Start (char *service)
{
int stat;
SOCKET tcpSocket,udpSocket;
char msg[256];
stat=_StartServerDaemon(service,
10,
// timeout en réception : 60 secondes par défaut
"",
// no log file
0,
// no client data
NULL,
// Constructor=NULL (no client data)
NULL,
// Destructor=NULL (no client data)
Dispatch, //
Dispatch function written above
AcceptConnection, // Acceptation function written above
udpManager, // udpManager
function written above
NULL,
// registration information
&tcpSocket, // tcp
socket created by this function if successful
&udpSocket); // udp socket
created by this function if successful
// An error has occured ! print the error message and leave.
if (!stat) {
_GetErrMsg(msg);
printf("%s\n",msg);
return;
}
// Now start the infinite loop of the server
_ServerMainLoop(NULL);
// The program should never reach this point !
_StopServerDaemon(tcpSocket,udpSocket);
}
//-----------------------------------------------------------------------------
int main (int argc, char **argv)
{
if (argc!=2) {
printf("usage : %s <service>\n",argv[0]);
return 0;
}
Start(argv[1]);
return 0;
}
Client example
Here is a listing of a simple client that can be used with the server
described above.
//-----------------------------------------------------------------------------
// This program illustrates a simple tcp/udp client implementation
//-----------------------------------------------------------------------------
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <time.h>
#include <rpcdc.h>
//-----------------------------------------------------------------------------
// Here is a definition of a structure that must be transmitted
to the server
// One possibility is to develop a specific XDR function, used
with transmit/
// receive functions
//-----------------------------------------------------------------------------
typedef struct _TEST {
int i1;
int i2;
int i3;
float f;
double d;
} TEST;
//-----------------------------------------------------------------------------
// First write the XDR function - standard structure
// The parameters are as follows :
// h : (void *) points to the host
binary representation of the data
// n : (void *) points to the network
binary representation of the data
// code : indicates the operation
to perform (3 possibilities)
//
--> XDR_ENCODE : conversion h -> n
//
--> XDR_DECODE : conversion n -> h
//
--> XDR_MEMORY : just returns the size of the object
//-----------------------------------------------------------------------------
size_t _xdr_TEST (void *h, void *n, int code)
{
TEST *hi=(TEST *)h;
// first convert pointers
char *ni=(char *)n;
size_t size;
switch (code) {
case XDR_ENCODE:
case XDR_DECODE:
size=_xdr_int(NULL,NULL,XDR_MEMORY);
_xdr_int((void *)&hi->i1,(void
*)ni,code); ni+=size;
_xdr_int((void *)&hi->i2,(void
*)ni,code); ni+=size;
_xdr_int((void *)&hi->i3,(void
*)ni,code); ni+=size;
size=_xdr_float(NULL,NULL,XDR_MEMORY);
_xdr_float((void *)&hi->f,(void
*)ni,code); ni+=size;
size=_xdr_double(NULL,NULL,XDR_MEMORY);
_xdr_double((void *)&hi->d,(void
*)ni,code); ni+=size;
return 0;
case XDR_MEMORY:
default:
return 3*_xdr_int(NULL,NULL,XDR_MEMORY)+
_xdr_float(NULL,NULL,XDR_MEMORY)+
_xdr_double(NULL,NULL,XDR_MEMORY);
}
}
//-----------------------------------------------------------------------------
// Now the function to send a TEST structure becomes very simple
!
// The following example returns 1 if success, 0 if a problem occurs.
// Binary conversion is automatically performed through the XDR
routine
// written above.
// Warning : remember to call _rpc_flush() !
//-----------------------------------------------------------------------------
int _rpcsend_TEST (SOCKET Socket,
RPC_MSG *rpc_msg, XDR_BUFFER *xdr_buffer,
TEST *TestParameter)
{
return _rpcsend_buffer(Socket,rpc_msg,xdr_buffer,TestParameter,_xdr_TEST)==
_xdr_TEST(NULL,NULL,XDR_MEMORY);
}
//-----------------------------------------------------------------------------
// Similarly, the function to receive a TEST structure is also
simple.
// Binary conversion is automatically performed through the XDR
routine
// written above.
//-----------------------------------------------------------------------------
int _rpcrecv_TEST (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
TEST *TestParameter)
{
return _rpcrecv_buffer(Socket,xdr_buffer,TestParameter,_xdr_TEST)==
_xdr_TEST(NULL,NULL,XDR_MEMORY);
}
//-----------------------------------------------------------------------------
// tcp client implementation
//-----------------------------------------------------------------------------
void mainTCP (char *server, char *service)
{
SOCKET Socket;
// to communicate with the server
RPC_MSG rpc_msg;
// for transmission buffering
XDR_BUFFER xdr_buffer;
// for XDR buffering
char msg[256];
int ans;
time_t t;
TEST Test;
time(&t);
// Initialization of the TEST structure
Test.i1=10;
Test.i2=17;
Test.i3=25;
Test.f=3.14159f;
Test.d=2.7182818;
// Connection request to the specified server, with the specified
service
Socket=_StartTCPClient(server,
service,
10,
&rpc_msg,
&xdr_buffer);
// An error occured, or the connection has been rejected
if (Socket==0) {
_GetErrMsg(msg);
printf("%s\n",msg);
return;
}
// Now the connection has been accepted !
// The first int (value 1) corresponds to the first rpc message
transmitted to the server
_rpcsend_int(Socket,&rpc_msg,&xdr_buffer,1);
// This message also uses an additionnal parameter (int) : here
the local time
_rpcsend_int(Socket,&rpc_msg,&xdr_buffer,(int)t);
// The last part of the message is made of the TEST structure defined
above
_rpcsend_TEST(Socket,&rpc_msg,&xdr_buffer,&Test);
// flushing is required !
_rpc_flush(Socket,&rpc_msg);
// Now I am waiting for the answer coming from the server !
// In this example, the first int is modified and returned, same
for the TEST structure.
_rpcrecv_int(Socket,&xdr_buffer,&ans);
_rpcrecv_TEST(Socket,&xdr_buffer,&Test);
printf("Message sent to server : %d\n",t);
printf("Server answered
: %d\n",ans);
printf("New TEST
: %d %d %d %g %lg\n",Test.i1,Test.i2,Test.i3,Test.f,Test.d);
// OK ! seems to work, bye !
_StopTCPClient(Socket,&rpc_msg,&xdr_buffer);
}
//-----------------------------------------------------------------------------
// udp client implementation
//-----------------------------------------------------------------------------
void mainUDP (char *service)
{
SOCKET udpSocket;
sockaddr_in bcast_addr,src_addr;
long int udpQuery;
int end,stat,len;
struct hostent *host;
time_t t1,t2;
struct timeval timeout={0,0};
char sz_info[256];
struct {
long int udpResponse;
char szb[128];
} udp;
// Creation of the socket corresponding to the specified service
udpSocket=_StartUDPClient(service,10,&bcast_addr);
if (udpSocket==0) {
_GetErrMsg(sz_info);
printf("%s\n",sz_info);
return;
}
// The udp message is 32 bits long, the value is just 1 in this
example
udpQuery=htonl(1);
stat=sendto(udpSocket,(char *)&udpQuery,sizeof(long
int),0,
(const struct sockaddr *)&bcast_addr,sizeof(sockaddr_in));
if (stat!=sizeof(long int)) {
_StopUDPClient(udpSocket);
return;
}
// Now I am waiting for answers coming from the different servers,
max. delay 10 seconds
time(&t1);
end=0;
do {
switch (_socket_ready_r(udpSocket,&timeout))
{
case -1:
// this is an error !
end=1;
break;
case 0:
// no error, socket not ready !
time(&t2);
end=(t2-t1)>10;
break;
default:
// no error, socket ready !
len=sizeof(src_addr);
stat=recvfrom(udpSocket,(char *)&udp,sizeof(udp),0,
(struct sockaddr *)&src_addr,&len);
if (stat==sizeof(udp)) {
udp.udpResponse=ntohl(udp.udpResponse);
switch (udp.udpResponse) {
case 2:
// the server answers 2 (1+udpQuery) : good !
strcpy(sz_info,udp.szb);
break;
default:
strcpy(sz_info,"");
}
if (strlen(sz_info)!=0) {
host=gethostbyaddr((char *)&src_addr.sin_addr,sizeof(struct in_addr),PF_INET);
if (host!=NULL) printf("%s : ",host->h_name);
else
printf("%s : ",inet_ntoa(src_addr.sin_addr));
printf("%s\n",sz_info);
}
}
}
} while (!end);
_StopUDPClient(udpSocket);
}
//-----------------------------------------------------------------------------
// main function
//-----------------------------------------------------------------------------
int main (int argc, char **argv)
{
if (argc!=3) {
printf("usage : %s <server>
<service> for tcp test\n",argv[0]);
printf("usage : %s -
<service> for udp test\n",argv[0]);
return 0;
}
if (strcmp(argv[1],"-")==0) mainUDP(argv[2]);
else
mainTCP(argv[1],argv[2]);
return 0;
}
Description of the XDR functions
The XDR functions all have the same structure :
The different functions are :
for int variables : | size_t _xdr_int (void *h, void *n, int code); |
for unsigned int variables : | size_t _xdr_uint (void *h, void *n, int code); |
for short int variables : | size_t _xdr_short (void *h, void *n, int code); |
for long int variables : | size_t _xdr_long (void *h, void *n, int code); |
for char variables : | size_t _xdr_char (void *h, void *n, int code); |
for float variables : | size_t _xdr_float (void *h, void *n, int code); |
for double variables : | size_t _xdr_double (void *h, void *n, int code); |
Description of the send/receive functions
size_t _rpcsend_buffer (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
void *Buffer,
size_t (*xdr_func)(void *, void *, int));
This function sends the content of the specified buffer to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
Buffer : points
to the buffer to be sent
xdr_func : address of
the user defined XDR routine
Return value : 0 if an error occurs
: >0 if successful (number of bytes sent)
size_t _rpcrecv_buffer (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
void *Buffer,
size_t (*xdr_func)(void *, void *, int));
This function receives data from a socket a stores it to the specified buffer. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
Buffer : points
to the buffer to receive
xdr_func : address of
the user defined XDR routine
Return value : 0 if an error occurs
: >0 if successful (number of bytes received)
size_t _rpcsend_buffer (SOCKET Socket,
RPC_MSG *rpc_msg,
char *Buffer,
size_t Len);
This function sends the content of the specified buffer to a socket, without XDR conversion. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
Buffer : points
to the buffer to be sent
Len
: number of bytes to be sent
Return value : 0 if an error occurs
: >0 if successful (number of bytes sent)
size_t _rpcrecv_buffer (SOCKET Socket,
char *Buffer,
size_t Len);
This function receives data from a socket a stores it to the specified buffer, without XDR conversion. The parameters are :
Socket : identifies
the socket from which the data must be read
Buffer : points
to the buffer to receive
Len
: number of bytes to receive
Return value : 0 if an error occurs
: >0 if successful (number of bytes received)
int _rpc_flush (SOCKET Socket,
RPC_MSG *rpc_msg);
To avoid some lost of time during transfer of the information through
the network, the data to be sent are first stored to an internal buffer.
Once this buffer is full, it is automatically flushed, thus resulting in
an effective transmission to the destination socket.
This function can be called at any moment, it allows to force flushing
and effective transmission to the destination socket. Using this function
is required if the total amount of data to transfer is less than the internal
buffer size (8192 bytes). The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
Return value : 0 if an error occurs
: >0 if successful (number of bytes received)
int _rpcsend_int (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
int I);
This function sends a int to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
I
: the int value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_int (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
int *I);
This function receives a int from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
I
: points to the int value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_uint (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
unsigned int I);
This function sends a uint to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
I
: the uint value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_uint (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
unsigned int *I);
This function receives a uint from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
I
: points to the uint value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_long (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
long I);
This function sends a long to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
I
: the long value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_long (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
long *I);
This function receives a long from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
I
: points to the long value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_short (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
short I);
This function sends a short to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
I
: the short value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_short (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
short *I);
This function receives a short from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
I
: points to the short value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_char (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
char C);
This function sends a char to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
C
: the char value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_char (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
char *C);
This function receives a char from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
C
: points to the char value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_string (SOCKET Socket,
RPC_MSG *rpc_msg,
char *S,
size_t SLen);
This function sends a character string to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
S
: points to the character string to be sent
SLen
: length of S
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_string (SOCKET Socket,
char *S,
size_t SLen);
This function receives a character string from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
S
: points to the character string to be read
SLen
: length of S
Return value : 0 if an error occurs
: 1 if successful
Warning : this function assumes that the length of the character string is known !
int _rpcsend_float (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
float X);
This function sends a float to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
X
: the float value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_float (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
float *X);
This function receives a float from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
X
: points to the float value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_double (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer,
double X);
This function sends a double to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
xdr_buffer : points to a user structure
for XDR buffering
X
: the double value to be sent
Return value : 0 if an error occurs
: 1 if successful
int _rpcrecv_double (SOCKET Socket,
XDR_BUFFER *xdr_buffer,
double *X);
This function receives a double from a socket. The parameters are :
Socket : identifies
the socket from which the data must be read
xdr_buffer : points to a user structure
for XDR buffering
X
: points to the double value to be read
Return value : 0 if an error occurs
: 1 if successful
int _rpcsend_tabfloat (SOCKET Socket,
RPC_MSG *rpc_msg,
float *X,
long int N,
int RestoreData);
This function sends a series of float to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
X
: points to the series of float to be sent
N
: number of float values to be sent
RestoreData : specifies if the data must
be restored or not
Return value : 0 if an error occurs
: 1 if successful
Remarks :
int _rpcrecv_tabfloat (SOCKET Socket,
float *X,
long int N);
This function reads a series of float from a socket. The parameters are :
Socket : identifies
the destination socket
X
: points to the series of float to be read
N
: number of float values to be read
Return value : 0 if an error occurs
: 1 if successful
Warning : this function assumes that the number of values to be read is known !
int _rpcsend_tabdouble (SOCKET Socket,
RPC_MSG *rpc_msg,
double *X,
long int N,
int RestoreData);
This function sends a series of double to a socket. The parameters are :
Socket : identifies
the destination socket
rpc_msg : points
to a user structure for internal buffering
X
: points to the series of double to be sent
N
: number of double values to be sent
RestoreData : specifies if the data must
be restored or not
Return value : 0 if an error occurs
: 1 if successful
Remarks :
int _rpcrecv_tabdouble (SOCKET Socket,
double *X,
long int N);
This function reads a series of double from a socket. The parameters are :
Socket : identifies
the destination socket
X
: points to the series of double to be read
N
: number of double values to be read
Return value : 0 if an error occurs
: 1 if successful
Warning : this function assumes that the number of values to be read is known !
int _socket_ready_r (SOCKET Socket,
struct timeval *timeout);
This function determines if a socket is ready for reading. The parameters are :
Socket : identifies
the socket
timeout : points
to a struct timeval specifying the timeout
Return value : -1 if an error occurs
: 0 if no error occurs and the socket is not ready for reading
: 1 if no error occurs and the socket is ready for reading
Remark : timeout can be NULL, in such case, this function blocks until an event occurs ; it can be also set as {0,0} to specify an immediate return of the function.
int _socket_ready_w (SOCKET Socket,
struct timeval *timeout);
This function determines if a socket is ready for writting. The parameters are :
Socket : identifies
the socket
timeout : points
to a struct timeval specifying the timeout
Return value : -1 if an error occurs
: 0 if no error occurs and the socket is not ready for writting
: 1 if no error occurs and the socket is ready for writting
Remark : timeout can be NULL, in such case, this function blocks until an event occurs ; it can be also set as {0,0} to specify an immediate return of the function.
Additionnal definitions (these are not real functions) :
#define rpcrecv_ulong(S,X,I) rpcrecv_long(S,X,(long
*)I)
#define rpcsend_ulong(S,R,X,I) rpcsend_long(S,R,X,(long)I)
#define rpcrecv_ushort(S,X,I) rpcrecv_short(S,X,(short
*)I)
#define rpcsend_ushort(S,R,X,I) rpcsend_short(S,R,X,(short)I)
#define rpcrecv_bool
rpcrecv_int
#define rpcsend_bool
rpcsend_int
Description of the server specific functions
void _ServerMainLoop (_REG_INFO *RegInfo);
This function initiates the main loop (infinite loop) of any server application. It has only one parameter :
RegInfo : a pointer to a _REG_INFO structure (see Software Registration)
Warning : the server must have been started.
int _StartServerDaemon (char *service,
int max_timeout,
char *logfile,
size_t bufsize,
void (*Constructor)(void *),
void (*Destructor)(void *),
void (*Dispatch)(int,int),
int (*AcceptConnection)(char *),
void (*udpManager)(SOCKET),
_REG_INFO *RegInfo,
SOCKET *tcpSocket,
SOCKET *udpSocket);
This function starts the server daemon. The parameters are :
service
: character string identifying the tcp/udp service to use
max_timeout :
specifies
the maximum timeout, in seconds
logfile
: character string identifying the log file
bufsize
: specifies the size of an internal buffer associated to each connected
client (can be 0)
Constructor :
this
function is called after allocation of the client internal buffer (can
be NULL)
Destructor
: this function is called before desallocation of the client internal
buffer (can be NULL)
Dispatch
: this function is called each time a message is received from the
network
AcceptConnection : this function is called
before accepting a connection
udpManager
: this function is called each time a message is received on the udp
socket (if present)
RegInfo
: a pointer to a _REG_INFO structure (see Software Registration)
tcpSocket
: points to the socket used for tcp connections
udpSocket
: points to the socket used for udp connections (can be NULL)
void _StopServerDaemon (SOCKET tcpSocket,
SOCKET udpSocket);
This function stops a running server daemon and closes the corresponding sockets. The two parameters are
tcpSocket : identifies the socket
used for tcp connections
udpSocket : identifies the
socket used for udp connections
int _GetClientInfo (int idClient,
SOCKET *socket,
RPC_MSG **rpc_msg,
XDR_BUFFER **xdr_buffer,
char **client_buffer);
This function retrieves some client specific informations ; it should be the first call of the Dispatch function implemented by the server. The parameters are :
idClient : identifies
the client (internal use for the server)
socket
: points to the socket used for communications with the corresponding
client
rpc_msg
: points to the RPC_MSG structure of the client
xdr_buffer : points to
the XDR_BUFFER structure of the client
client_buffer : points to the data allocated
for each client
Return value : 0 if an error occurs
: 1 if successful
Description of the client specific functions
SOCKET _StartTCPClient (char *servername,
char *service,
int max_timeout,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer);
This function initiates the client-side of the communication with a server on the network (tcp connection). The parameters are :
servername : character
string identifying the name of the server to use
service
: character string identifying the tcp service to use
max_timeout : specifies the
maximum timeout, in seconds
rpc_msg
: points to the RPC_MSG structure of the client
xdr_buffer : points to
the XDR_BUFFER structure of the client
SOCKET _StartUDPClient (char *service,
int max_timeout,
sockaddr_in *bcast_addr);
This function initiates the client-side of the communication with a server on the network (udp connection). The parameters are :
service :
character
string identifying the udp service to use
max_timeout : specifies the
maximum timeout, in seconds
bcast_addr : points to
the broadcast address (can be NULL)
int _StopTCPClient (SOCKET Socket,
RPC_MSG *rpc_msg,
XDR_BUFFER *xdr_buffer);
This function stops a tcp client. The parameters are :
Socket
: identifies the communication socket
rpc_msg
: points to the RPC_MSG structure of the client
xdr_buffer : points to
the XDR_BUFFER structure of the client
Return value : 0 if an error occurs
: >0 if successful (socket identification)
void _StopUDPClient (SOCKET Socket);
This function stops a udp client. The parameters are :
Socket : identifies the communication socket
Description of the common functions
void _GetErrMsg (char *msg);
This function copies to the character string msg the last error message.
int _rpc_gethostname (char *hostname,
int maxlen,
char *ipaddr);
This function determines the ip address of the specified host identified
by its name hostname.
If hostname is an empty character string, this function also
returns the ip name of the local computer ; in such case the maximum length
of the variable is required (maxlen). In any other cases, this
parameter is ignored.
The character string ipaddr is returned by the function, it
contains the ip address of the local computer/specified host. The character
string must be declared as an array of minimum length 16.
The function returns 1 in case of success, 0 if an error occurs.